﻿#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<set>
#include<map>
using namespace std;

/*

//int main()
//{
//	//去重 + 升序排序
//	set<int> s;   //默认是升序
//	//去重 + 降序排序
//	//set<int,greater<int>> s;   //传仿函数的降序   就会变为降序
//	s.insert(5);
//	s.insert(2);
//	s.insert(7);
//	s.insert(5);
//
//	//遍历  用迭代器(迭代器版本遍历)
//	//set<int>::iterator it = s.begin();
//	//while (it != s.end())
//	//{
//	//	cout << *it << " ";
//	//	it++;
//	//}
//
//	//遍历  用auto 自适应迭代器类型
//	auto it = s.begin();
//	while(it!=s.end())
//	{
//		//*it = 1;    这一步会报错   因为不支持修改
//
//		cout << *it << " ";
//		++it;
//	}
//	cout << endl;
//
//
//	for (auto it : s)
//	{
//		cout << it << " ";
//		++it; 
//	}//默认是升序排   而且是默认升序排+去重
//	cout << endl;
//
//	//也支持这样插入
//	s.insert({ 2,1,8,3,9,2,6 });
//	for (auto it : s)
//	{
//		cout << it << " ";
//		++it;
//	}//默认是升序排   而且是默认升序排+去重
//	cout << endl;
//
//	//set不仅支持整型   也支持字符串
//	//下面的实际是调用构造	  void insert(initializer_list<value_type> il);
//	set<string> strset = { "sort","add","insert" };     //这是构造了一个临时对象  再进行拷贝构造  优化成为了直接构造
//	//set<string> strset ({ "sort","add","insert" });     //直接构造
//	for (auto& e : strset)
//	{
//		cout << e << " ";
//	}
//	//字符串的比较是按照ascii进行比较
//
//	return 0;
//}

*/

/*

int main()
{
	//查找 find   找到返回迭代器   找不到返回end   时间复杂  logN
	set<int> s = { 4,2,7,2,8,5,9 };
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	//删除最小值(只需要传参传上迭代器)
	s.erase(s.begin());
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	//直接删除x
	//int x;
	//cin >> x;
	//int num=s.erase(x);
	//if (num == 0)
	//{
	//	cout << x << "不存在！" << endl;
	//	for (auto e : s)
	//	{
	//		cout << e << " ";
	//	}
	//	cout << endl;
	//}
	//else
	//{ 
	//	cout << x << "删除成功" << endl;
	//	for (auto e : s)
	//	{
	//		cout << e << " ";
	//	}
	//	cout << endl;
	//}


	int x;
	cin >> x;
	auto pos = s.find(x);    //先进行查找这个数
	if (pos != s.end())
	{
		s.erase(pos);    //一旦删除（删除后访问）   迭代器就会失效   
	}
	else
	{
		cout << x << "不存在！" << endl;
	}


	//查找(都能查找x)   
	//关于算法库的查找   时间复杂度：O(N)   遍历这段区间  只是适用于各种容器
	auto pos1 = find(s.begin(), s.end(), x);
	
	//set自身实现的查找   时间复杂度 O(logN)
	auto pos2 = s.find(x);   

	
	//利用count间接实现快速查找(只判断是否在内  count可以快速查找   找到返回1   找不到返回0)
	cin >> x;
	if (s.count(x))   
	{
		cout << x << "在内" << endl;
	}
	else
	{
		cout << x << "不在内" << endl;
	}

//这两个是查找一段迭代器区间的
	//lower_bound  返回大于等于val位置的迭代器
	//upper_bound  返回大于val位置的迭代器
}

*/

/*

int main()
{
	set<int> myset;
	for (int i = 1; i < 10; i++)
	{
		myset.insert(i * 10);   //10  20  30  40  50  60  70  80  90 
	}
	for (auto e : myset)
	{
		cout << e << " ";
	}
	cout << endl;

	//返回 >= 30
	auto itlow = myset.lower_bound(30);
	//返回 > 60
	auto itup = myset.upper_bound(60);

	//找到这段范围区间  然后就可以进行删除  删除了30-60的区间内
	myset.erase(itlow, itup);
	for (auto e : myset)
	{
		cout << e << " ";
	}
	cout << endl;
	
	return 0;
}

*/

/*

int main()
{
	//注意：multiset和set不同的   multiset只排序  不去重
	multiset<int> s = { 4,2,7,2,4,8,4,5,4,9 };
	auto it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;


	//相比set不同的是  x可能查找会存在多个   find查找中序的第一个
	//int x;
	//cin >> x;
	//auto pos = s.find(x);
	////找出之后打印出所有的x
	//while (pos != s.end() && *pos == x)
	//{
	//	cout << *pos << " ";
	//	++pos;
	//}
	//cout << endl;

	int x;
	cin >> x;
	cout << s.count(x) << endl;

	s.erase(x);   //这个会直接删除所有的x
	//auto pos = s.find(x);
	//while (pos != s.end() && *pos == x)
	//{
	//	pos = s.erase(pos);    //因为删除了当前位置   返回当前位置的下一个位置的迭代器
	//}
	//cout << endl;    
	//这个是遍历查找所有的x

	//count是返回值的数量

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

*/

/*

int main()
{
	//initializer_list 构造 初始化
	map<string, string> dict = { {"left","左边"},{"right","右边"},{"insert","插入"},{"string","字符串"} };
	//上面的多参数支持隐式类型转换（隐式类型转换成为了pair    调用构造+拷贝构造）
	//调用的是   map<initializer_list<value_type> il   构造版本     外围的是initializer_list
	//value_type  是pair    里面的是pair的双参数的隐式类型转换    
	//typedef pair<const key,T> value_type;

	//map的插入数据的方式1    先构造一个map容器    然后构造一个有名的pair成员   然后调用容器函数进行插入
	map<string, string> dict;
	pair<string, string> kv1("first", "第一个");
	dict.insert(kv1);  
	
	//map插入方式2  直接进行插入
	dict.insert(pair<string, string>("second", "第二个"));     //这是自己构造匿名对象
	
	//map插入方式3  make_pair  进行插入
	dict.insert(make_pair("sort", "排序"));   //make_pair 是一个模板   

	//C++ 11支持的直接插入对象（单参数构造支持隐式类型转换   花括号会隐式类型转换成为pair）
	dict.insert({ "auto","自动的" });
	dict.insert({ "auto","自动的xxxx" });    //上面的不会被更改   插入失败   因为插入的时候只看key   value不相等不会进行更新

	
	//迭代器打印(若存的是结构  就用箭头  别的容器大都不用->   但是map用的很多)
	map<string, string>::iterator it = dict.begin();
	while (it != dict.end())
	{
		//注意：这个方式支持修改value   但是不支持修改key
		//it->first += "xx";    //这个不支持修改
		it->second += "xx";

		//这不能直接  进行解引用打印输出的  因为里面有两个对象（一个结构体）   类似于解引用得到一个节点类型
		//故这里的打印需要修改

		//cout << (*it).first << ":" << (*it).second << endl;
		
		cout << it->first << ":" << it->second << endl;   

		cout << it.operator->()->first << ":" << it.operator->()->second << endl;
		//本质是下面这样的两个箭头  it.operator->()->first     上面省略了一个箭头
		cout << endl;
		++it;
	}
	cout << endl;

	return 0;
}

*/

/*

int main()
{
	//利用find和iterator修改功能   统计水果出现的次数
	string arr[] = { "苹果","西瓜","苹果","西瓜","苹果","苹果","西瓜", "苹果", "香蕉", "苹果", "香蕉" };
	map<string, int> countMap;
	for (const auto& str : arr)
	{
		////先查找水果在不在map 
		////不在，说明水果第一次出现   插入{ 水果，1 }
		////在则查找到的节点中水果对应的次数++
		
		//auto ret = countMap.find(str);
		//if (ret == countMap.end())
		//{
		//	//多参数隐式类型转换
		//	countMap.insert({ str,1 });
		//}
		//else
		//{
		//	ret->second++;
		//}     //python不合适   下面的[]方式    只支持这种方式

		//在C++中   map统计次数可以使用上面的方式   也可以使用下面的方式（更简）
		countMap[str]++;
		//效果和上面的一样
	}

	for (const auto& e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	}
}

*/

/*

//测试 map中 []的作用
int main()
{
	map<string, string> dict;
	dict.insert(make_pair("sort", "排序"));

	//key不存在 -> 插入 {"insert",string()}
	dict["insert"];    //这里充当的就是插入的功能作用

	// 插⼊+修改 
	dict["left"] = "左边";

	// 修改 （因为这个本身就已经存在了   所以就是单纯的修改）
	dict["left"] = "左边、剩余";
	
	// key存在->查找 (确定值在内才能这样使用   用作查找作用    否则就是插入)
	cout << dict["left"] << endl;

	//这个是插入
	cout << dict["sort"] << endl;

	return 0;
}

*/


//测试multimap
int main()
{
	multimap<string, string> dict;   //可以认为这种插入必定成功   因为可以相同也可不同
	dict.insert({ "sort","排序" });
	dict.insert({ "sort","排序" });
	dict.insert({ "sort","排序" });
	dict.insert({ "sort","排序" });
	dict.insert({ "sort","排序" });
	//multimap的erase也是把所有的key相同的都删除
	dict.erase("sort");

	return 0;
}
 